"use strict"
/**
 * @name nutaku
 * N站(nutaku)
 签名验证:https://nutakudoc.atlassian.net/wiki/spaces/ND/pages/190578689/OAuth+Signature+Validation
 支付文档:https://nutakudoc.atlassian.net/wiki/spaces/ND/pages/18284546/Payment+Service
 登陆文档:https://nutakudoc.atlassian.net/wiki/spaces/ND/pages/18153476/Calling+an+External+Server
 */
const fs = require('fs');
const crypto = require('crypto');

const querystring = require('querystring');
const OAUTH = {};
//订单记录分隔符
const ORDERATTACHSPLIT = "#"

exports.format = {
    "id":'nutaku',
    "name":"N站(nutaku PC)",
    "fields" : {
        appid :{'type':'string','val':'',"name":"App ID"},
        appkey :{'type':'string','val':'',"name":"consumer_key"},
        secret :{'type':'string','val':'',"name":"consumer_secret"},
        SCRT :{'type':'string','val':'',"name":"登陆证书(Sandbox)"},
        PCRT :{'type':'string','val':'',"name":"登陆证书(Production)"},
    }
}


/**
 * @name login
 */

exports.login = function(){
    let oauth_signature = this.get("oauth_signature","string");
    if(!oauth_signature){
        return this.error("oauth_signature emprt")
    }
    let body= Object.assign({},this.req.body || {},this.req.query);
    delete body['oauth_signature'];

    return OAUTH.RSA.call(this,body,oauth_signature).then(ret=>{
        return this.get("opensocial_viewer_id","string");
    })
}


/**
 * @name createOrder
 * 创建订单
 */
exports.orderCreate = function(config,notify){
    //记录订单
    //this.debug =1
    let attach = config['attach'];
    let orderid = config['orderid'];
    return Promise.resolve().then(()=>{
        let orderData = [attach,config['rmb']].join(ORDERATTACHSPLIT)
        let orderModel = this.model.redis("order",this.branch);
        return orderModel.set(orderid,orderData, 600)
    }).then(()=>{
        let data = {};
        data["rmb"] = config['rmb'];
        data["attach"] = orderid;               //自己记录attach透传参数为orderid
        data["orderid"] = orderid;
        // data["notify"] = notify;
        return data;
    })
}



/**
 * @name orderNotify
 * 支付回调
 */

exports.orderNotify = function(){
     // this.debug = 1;
     // console.debug("body",this.req.method,this.req.body)
     // console.debug("query",this.req.method,this.req.query)

    if(this.req.method === 'POST'){
        //this.library("debug",'orderNotify POST',this.req.body);
        return PC_Notify_Submit.call(this);
    }
    else{
        //this.library("debug",'orderNotify POST',this.req.query);
        return PC_Notify_Goods.call(this);
    }
}

//AMOUNT
//PC端订单确认
function PC_Notify_Submit() {
    let ITEMS = this.get("ITEMS","json");
    let AMOUNT = this.get("AMOUNT","int");
    let PAYMENT_ID = this.get("PAYMENT_ID","string");
    if(!Array.isArray(ITEMS) || ITEMS.length === 0){
        return this.error("PC_Notify_Submit ITEMS error",ITEMS)
    }
    if(!AMOUNT){
        return this.error("PC_Notify_Submit AMOUNT empty");
    }
    if(!PAYMENT_ID){
        return this.error("PC_Notify_Submit PAYMENT_ID empty");
    }

    let orderid = ITEMS[0]['SKU_ID']||'';
    if(!orderid){
        return this.error("orderid empty")
    }
    let orderModel = this.model.redis("order",this.branch);

    return Promise.resolve().then(()=>{
        return verify_order.call(this,PAYMENT_ID)
    }).then(()=>{
        return orderModel.get(orderid)
    }).then(attach=>{
        if(!attach){
            return this.error("orderid not exist")
        }
        let arr = attach.split(ORDERATTACHSPLIT);
        if(arr.length !=2){
            return this.error("attach error",PAYMENT_ID);
        }
        let rmb = parseInt(arr[1]);
        if(rmb != AMOUNT){
            return this.error("order AMOUNT error",rmb,AMOUNT);
        }
        return orderModel.set(PAYMENT_ID,attach, 3600);
    }).then(()=>{
        return orderModel.del(orderid)
    }).then(()=>{
        return this.error("success",null)
    })
}

//PC端订单发货
//只有一个payment_id业务参数
function PC_Notify_Goods() {
    let payment_id = this.get("payment_id","string");
    let result= {"orderid":payment_id};
    let orderModel = this.model.redis("order",this.branch);
    return Promise.resolve().then(()=>{
        return verify_order.call(this,payment_id)
    }).then(()=>{
        return orderModel.get(payment_id)
    }).then(attach=>{
        if(!attach){
            return this.error("PC_Notify_Goods payment_id not exist",payment_id);
        }
        let arr = attach.split(ORDERATTACHSPLIT);
        if(arr.length !=2){
            return this.error("PC_Notify_Goods attach error",payment_id,attach);
        }
        result['attach'] = arr[0];
        result['amount'] = parseInt(arr[1]);
    }).then(()=>{
        return result;
    })
}


/**
 * @name orderResult
 * 回调信息
 */

exports.orderResult= function(err,ret){
    this.output = 'application/json';
    if(err && err['err']!=='success' ){
        this.status = 500;
        return this.error(err);
    }
    let data = {"response_code":"OK"};
    if(ret && ret['orderid']){
        data['payment_id'] = ret['orderid'];
        let orderModel = this.model.redis("order",this.branch);
        orderModel.del(data['payment_id']);
    }
    return data;
}




function verify_order(PAYMENTID) {
    let Authorization = this.req.header("Authorization");
    if(!Authorization){
        return this.error("Authorization empty",PAYMENTID);
    }
    Authorization = Authorization.replace("OAuth ","");
    let OAuthParam = querystring.parse(Authorization,',','=');
    for(let k in OAuthParam){
        OAuthParam[k] = OAuthParam[k].substr(1,OAuthParam[k].length-2);
    }
    let oauth_signature = decodeURIComponent(OAuthParam['oauth_signature']);
    delete OAuthParam['realm'];
    delete OAuthParam['oauth_signature'];

    let body= Object.assign({},this.req.query,OAuthParam);
    return OAUTH.HMAC.call(this,body,oauth_signature)
}




OAUTH.HMAC = function(params,sign){
    let str = OAUTH.params.call(this,params);
    if(!this.opensdk.setting['secret']){
        return Promise.reject(`opensdk.setting.secret empty`)
    }
    let key = [encodeURIComponent(this.opensdk.setting['secret']),params['oauth_token_secret']||''].join("&");
    let mysign = crypto.createHmac('sha1', key).update(str).digest().toString('base64');
    if(mysign != sign){
        return  this.error("oauth_signature error");
    }
}



OAUTH.RSA = function (params,sign) {
    let crt = this.opensdk['status'] ? 'PCRT' : 'SCRT';
    return Promise.resolve().then(()=>{
        if(!this.opensdk.setting[crt]){
            return Promise.reject(`opensdk.setting.${crt} empty`)
        }
        return this.library("promise",fs.readFile,this.opensdk.setting[crt])
    }).then((PublicKey)=>{
        let verify = crypto.createVerify('RSA-SHA1');
        let str = OAUTH.params.call(this,params);
        return verify.update(str).verify(PublicKey, sign,"base64");
    }).then(ret=>{
        if(!ret){
            return this.error("oauth error")
        }
    })
}

OAUTH.params = function (params) {
    let Method = this.req.method;
    let urlArr = this.req.originalUrl.split('?');
    let urlStr = encodeURIComponent([this.req.protocol,'://',this.req.hostname,urlArr[0]].join(''));
    let keys = Object.keys(params).sort();
    let sPara = []
    for(let k of keys){
        let v = params[k];
        if(String(v).indexOf('/')>=0){
            v = encodeURIComponent(v);
        }
        sPara.push( k+"="+v);
    }
    let str = encodeURIComponent(sPara.join("&")) ;
    return [Method,urlStr,str].join("&")
}